
--[[
	**********************
	* SvFrame - thomasfn *
	**********************
	util.lua - Loads utility functions
]]

local files = files or Files

function string.explode( str, sep )
	if (sep == " ") or (not sep) then sep = "%s" end
	if (sep == "^") then sep = "%^" end
	local tmp = {}
	for token in string.gmatch( str, "[^" .. sep .. "]+" ) do
		tmp[ #tmp + 1 ] = token
	end
	return tmp
end

function table.removevalue( tbl, val )
	for key, v in pairs( tbl ) do
		if (v == val) then
			table.remove( tbl, key )
			return
		end
	end
end

function svr.NameToTitle( str )
	local words = str:explode( "_" )
	local tmp = {}
	for i=1, #words do
		local word = words[i]
		if (word and word ~= "") then
			tmp[ #tmp + 1 ] = word:sub( 0, 1 ):upper() .. word:sub( 2 ):lower()
		end
	end
	return table.concat( tmp, " " )
end

function svr.Time()
	return math.floor( os.time() / 1000 )
end

function svr.GetPlayers()
	return players.GetAll()
end

function svr.FindPlayers( str )
	local tmp = {}
	str = str:lower()
	local players = svr.GetPlayers()
	for _, ply in pairs( players ) do
		if (ply.Username == str) then return { ply } end
		if (ply.Username:lower():find( str )) then
			tmp[ #tmp + 1 ] = ply
		end
	end
	return tmp
end

function svr.PlayerByName( name, ply )
	local plist = svr.FindPlayers( name )

	if (#plist == 0) then
		return ply:ChatPrint( colour.Red, "No players found with that name." )
	end

	if (#plist > 1) then
		return ply:ChatPrint( colour.Red, "Multiple ("..(#plist)..") players found with that partial name." )
	end
	
	return plist[1]
end

function svr.ChatPrint( ply, ... )
	local args = { ... }
	
	--print( "---" )
	--svr.Print( svr.SerializeTable(args) )
	--print( "-----" )
	--svr.PrintTable( args )
	
	local message = {}
	for i=1, #args do
		local v = args[i]
		if (type(v) == "string") and (v:find( "%^" )) then
			local split = v:explode( "^" )
			for j=1, #split do
				local str = split[j]
				local tmp = ""
				local tmp2 = ""
				local numbermode = true
				for k=str:len(), 1, -1 do
					local char = str:sub( k, k )
					local digit = tonumber( char )

					if (not digit) then 
						numbermode = false
					end

					if (numbermode) then
						tmp = tmp .. char
					else
						tmp2 = tmp2 .. char
					end
				end
				
				tmp = tonumber( tmp:reverse() )
				
				if (tmp2 ~= "") then 
					table.insert( message, tmp2:reverse() )
				end
				
				if (tmp) then 
					table.insert( message, COL_ID[ tmp ] ) 
				end
			end
		elseif (type( v ) == "number") then
			table.insert( message, COL_ID[ v ] )
		else
			table.insert( message, tostring(v) )
		end
	end
	
	--[[for i=1, #message do
		if (type( message[i] ) == "string") and (tonumber(message[i])) then
			message[i] = message[i].."\0"
		end
	end]]
	
	--svr.PrintTable( message )
	
	--local message = args
	if (not ply) then
		local pls = players.GetAll()
		for k,pl in pairs(pls) do
			pl.Print(unpack( message ))
		end
		-- server.ChatAll(unpack(message)) -- this seems to be buggy.
	else
		ply.Print( unpack( message ) )
	end
end

function svr.CheckArg( args, id, typ )
	local val = args[id]
	local typ = typ:lower()
	if (typ == "number") then val = tonumber(val) end
	if (typ == "bool" and typ == "boolean") then val = tobool(val) end
	if (not val) then return false end
	if (typ == "string") then return string.len(val) > 0 end
	return true
end

function svr.CNick(ply)
	svr.Warning( "The function svr.CNick is obsolete! (" .. tostring( debug.getinfo( 2 ).source ) .. ")" )
	return ply.Username
end

function svr.TableToFile( filename, tbl )
	local fname = "lua/"..filename..".txt"
	local f, err = io.open( fname, "w")
	if(err) then
		return false, "Failed to open "..fname.." for writing!"
	end
	if(type(tbl) == "table") then
		f:write( "return "..svr.SerializeTable(tbl) )
	else
		f:close()
		return false, "No table was provided to write to "..fname.."!"
	end
	return true, "Success"
end

function svr.FileToTable( filename )

	local fname = "lua/"..filename..".txt"
	local f, err = io.open(fname, "r")
	if(err) then
		return false, "Failed to open "..fname.." for reading!"
	end
	
	local s = f:read("*a")
	f:close()
	local func = loadstring(s)
	if (not func) then return false, "File was empty or corrupt! (" .. fname .. ")" end
	return true, func()
end

function svr.SerializeTable(t, t_name, tab)
	tab = tab or "";
	t_name = t_name or ""
	if(type(t_name)=="string" and string.len(t_name) > 0) then
		t_name = t_name.." = "
	end
	out = tab..t_name.."{\n"
	for k, v in pairs(t) do
		local key = (type(k) == "string") and string.format("[%q]",k) or string.format("[%d]",k)
		if (type(v) == "table") then
			
			out = out..svr.SerializeTable(v, key, tab.."\t")..",\n"
		else
			local value = (type(v) == "string") and string.format("%q",v) or tostring(v)
			if (type(v) == "string" or type(v) == "number" or type(v) == "boolean") then
				out = out..tab.."\t"..key.." = "..value..",\n"
			end
		end

	end
	return out..tab.."}"
end

local cache = {}
function svr.SetPlayerPData( ply, key, value )
	if (type( ply ) == "string") then ply = { Username = ply } end
	local filename = "SvFrame/playerdata/" .. ply.Username
	local file = cache[ply] or Files.GetFile( filename, Files.Prop ) or Files.CreateFile( filename, Files.Prop )
	cache[ply] = file
	local t = type( value )
	if (t == "string") then
		file:SetString( key, value )
	elseif (t == "number") then
		file:SetNumber( key, value )
	elseif (t == "boolean") then
		file:SetBoolean( key, value )
	end
	file:Save()
end
function svr.GetPlayerPData( ply, key, t )
	if (type( ply ) == "string") then ply = { Username = ply } end
	local filename = "SvFrame/playerdata/" .. ply.Username
	local file = cache[ply] or Files.GetFile( filename, Files.Prop ) or Files.CreateFile( filename, Files.Prop )
	cache[ply] = file
	if (t == "string") then
		return file:GetString( key )
	elseif (t == "number") then
		return file:GetNumber( key )
	elseif (t == "boolean") then
		return file:GetBoolean( key )
	end
	return nil
end
function svr.GetPlayerPDataS( ply, key ) return svr.GetPlayerPData( ply, key, "string" ) end
function svr.GetPlayerPDataN( ply, key ) return svr.GetPlayerPData( ply, key, "number" ) end
function svr.GetPlayerPDataB( ply, key ) return svr.GetPlayerPData( ply, key, "boolean" ) end

function svr.PlayerData( ply )
	svr.Warning( "The function svr.PlayerData is obsolete! (" .. tostring( debug.getinfo( 2 ).source ) .. ")" )
	return ply
end

local blocktemp = {}
function svr.BlockData( block, dimension )
	if (not block) then return end
	local BlockData = block.X .. "" .. block.Y .. "" .. block.Z .. "" .. dimension
	if (not blocktemp[BlockData])then blocktemp[BlockData] = {} end
	return blocktemp[BlockData]
end

local MatTable = {}
-- TODO: Make this work with new enums
for key, tbl in pairs( {LOOKUP_TOOL, LOOKUP_ITEM}) do
	for name, id in pairs(tbl) do 
		if (string.find( name, "leather" )) then MatTable[ id ] = MAT_LEATHER end
		if (string.find( name, "wood" )) then MatTable[ id ] = MAT_WOOD end
		if (string.find( name, "stone" )) then MatTable[ id ] = MAT_STONE end
		if (string.find( name, "iron" )) then MatTable[ id ] = MAT_IRON end
		if (string.find( name, "gold" )) then MatTable[ id ] = MAT_GOLD end
		if (string.find( name, "diamond" )) then MatTable[ id ] = MAT_DIAMOND end
	end
end

function svr.GetMaterial(id)
	return MatTable[id]
end

function svr.TestHook( name )
	local function Test( ... )
		local args = { ... }
		print( "TestHook '" .. name .. "' was called with " .. #args .. " arguments." )
		for i=1, #args do
			print( i .. ": " .. tostring( args[i] ) .. " (" .. type( args[i] ) .. ")" )
		end
	end
	hooks.Add( name, "SvFrame_TestHook_" .. name, Test )
end

svr.Config = files.GetFile( "SvFrame/config/config", files.Prop ) or files.CreateFile( "SvFrame/config/config", files.Prop )